package com.huxiaohui.ssbx.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.aigc.multimodalconversation.AudioParameters;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.huxiaohui.ssbx.config.props.VoiceProperties;
import com.huxiaohui.ssbx.constants.ResponseConstants;
import com.huxiaohui.ssbx.service.IObjectStorageService;
import com.huxiaohui.ssbx.service.IVoiceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 语音服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class VoiceServiceImpl implements IVoiceService {

    private final VoiceProperties voiceProperties;
    private final IObjectStorageService objectStorageService;

    @Override
    public String processAudio(String sessionId, byte[] audioData) {
        try {
            log.debug("开始处理音频数据，SessionID: {}, 数据大小: {} bytes", sessionId, audioData.length);

            // 是否为WAV文件
            String url = "";
            if (isWav(audioData)) {
                url = objectStorageService.uploadBinaryAudioData(audioData, IdUtil.fastSimpleUUID() + ".wav");
            } else {
                audioData = opusToWav(audioData);
                url = objectStorageService.uploadBinaryAudioData(audioData, IdUtil.fastSimpleUUID() + ".wav");
            }
            if (url == null) {
                return ResponseConstants.ERROR_TAG + "上传音频失败";
            }

            String text = sst(url, voiceProperties.getApiKey(), "wav");
            log.info("语音识别结果: {}", text);
            return Objects.requireNonNullElse(text, ResponseConstants.ERROR_TAG + "语音识别失败");
        } catch (Exception e) {
            log.debug("处理音频数据失败", e);
            return  ResponseConstants.ERROR_TAG + "语音识别失败，请重试";
        }
    }


    /**
     * 判断是否为WAV文件（以RIFF开头）
     */
    private boolean isWav(byte[] bytes) {
        return bytes != null && bytes.length >= 44
                && bytes[0] == 'R' && bytes[1] == 'I' && bytes[2] == 'F' && bytes[3] == 'F'
                && bytes[8] == 'W' && bytes[9] == 'A' && bytes[10] == 'V' && bytes[11] == 'E';
    }

    /**
     * 语音转文本
     * @param url  音频地址（公网）
     * @param ak  七牛云ak
     * @param type 音频格式
     * @return
     */
    public String sst(String url, String ak,String type) {
        Map<String,Object> paramsMap = Map.of(
                "model","asr",
                "audio", Map.of("format",type,"url",url)
        );
        System.out.println(JSONUtil.toJsonStr(paramsMap));
        HttpRequest request = HttpRequest.post("https://openai.qiniu.com/v1/voice/asr")
                .header("Authorization", "Bearer " + ak)
                .header("Content-Type", "application/json")
                .body(JSONUtil.toJsonStr(paramsMap));
        HttpResponse response = request.execute();
        if (response.isOk()) {
            return JSONUtil.parseObj(response.body()).getByPath("data.result.text", String.class);
        } else {
            return null;
        }
    }

    /**
     * 将WebM/Opus字节数组转成WAV格式的二进制数组
     * @param opusData WebM/Opus二进制数据
     * @return WAV格式的二进制数组（包含完整WAV头和PCM数据）
     */
    public byte[] opusToWav(byte[] opusData) throws Exception {
        // 临时文件路径（使用系统临时目录，避免权限问题）
        String tempDir = System.getProperty("java.io.tmpdir");
        String tempOpusPath = tempDir + File.separator + "temp_opus_" + System.currentTimeMillis() + ".webm";
        String tempWavPath = tempDir + File.separator + "temp_wav_" + System.currentTimeMillis() + ".wav";

        try {
            // 1. 临时保存WebM/Opus数据（FFmpeg需要文件路径）
            FileUtils.writeByteArrayToFile(new File(tempOpusPath), opusData);

            // 2. 解码Opus并转成WAV（16-bit PCM）
            try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(tempOpusPath)) {
                grabber.start();

                // 配置输出WAV参数（16-bit单声道，保持原采样率）
                try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempWavPath, voiceProperties.getAudio().getChannels())) { // 1声道（单声道）
                    recorder.setFormat("wav");
                    recorder.setSampleRate(grabber.getSampleRate());
                    recorder.setAudioBitrate(voiceProperties.getAudio().getSampleRate());
                    recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE); // 16-bit小端PCM
                    recorder.start();

                    // 逐帧转换
                    org.bytedeco.javacv.Frame frame;
                    while ((frame = grabber.grabFrame()) != null) {
                        recorder.record(frame);
                    }
                }
            }

            // 3. 读取WAV文件为二进制数组
            return FileUtils.readFileToByteArray(new File(tempWavPath));

        } finally {
            // 4. 强制删除临时文件（无论转换成功与否）
            try {
                FileUtils.forceDelete(new File(tempOpusPath));
            } catch (IOException e) {
                log.error("临时文件删除失败: " + tempOpusPath, e);
            }
            try {
                FileUtils.forceDelete(new File(tempWavPath));
            } catch (IOException e) {
                log.error("临时文件删除失败: " + tempWavPath, e);
            }
        }
    }


    @Override
    public byte[] generateTTS(String sessionId, String text) {
        try {
            Map<String,Object> paramsMap = Map.of(
                    "audio",Map.of(
                            "voice_type",voiceProperties.getTts().getVoiceType(),
                            "encoding", voiceProperties.getTts().getEncoding(),
                            "speed_ratio", voiceProperties.getTts().getSpeedRatio()
                    ),
                    "request",Map.of("text",text)
            );
            HttpRequest request = HttpRequest.post("https://openai.qiniu.com/v1/voice/tts")
                    .header("Authorization", "Bearer " + voiceProperties.getApiKey())
                    .header("Content-Type", "application/json")
                    .body(JSONUtil.toJsonStr(paramsMap));
            HttpResponse response = request.execute();
            if (response.isOk()) {
                String audioBase64Data = JSONUtil.parseObj(response.body()).getByPath("data", String.class);
                // 1. 获取Base64标准解码器
                Base64.Decoder decoder = Base64.getDecoder();
                // 2. 解码Base64字符串，得到二进制数组（字节数组）
                return decoder.decode(audioBase64Data);

            } else {
                log.error("生成TTS音频失败: " + response.body());
                return null;
            }
        } catch (Exception e) {
            log.error("生成TTS音频失败", e);
            return null;
        }
    }

    @Override
    public byte[] generateTTS() {
        return simulateTextToSpeech();
    }

    /**
     * 模拟TTS音频生成
     */
    private byte[] simulateTextToSpeech() {
        try {
            // 生成简单的WAV格式音频数据
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            // WAV文件头
            byte[] header = createWavHeader(5000); // 根据文本长度估算音频长度
            baos.write(header);

            // 生成简单的音频数据（正弦波）
            int sampleRate = 16000;
            int duration = 2; // 根据文本长度计算持续时间
            int samples = sampleRate * duration;

            for (int i = 0; i < samples; i++) {
                double frequency = 440.0 + (i % 200); // 变化的频率
                double sample = Math.sin(2 * Math.PI * frequency * i / sampleRate);
                short sampleValue = (short) (sample * Short.MAX_VALUE * 0.3);

                // 小端序写入
                baos.write(sampleValue & 0xFF);
                baos.write((sampleValue >> 8) & 0xFF);
            }

            return baos.toByteArray();
        } catch (IOException e) {
            log.error("生成模拟TTS音频失败", e);
            return new byte[0];
        }
    }

    /**
     * 创建WAV文件头
     */
    private byte[] createWavHeader(int dataSize) {
        ByteBuffer header = ByteBuffer.allocate(44);
        header.order(ByteOrder.LITTLE_ENDIAN);

        // RIFF header
        header.put("RIFF".getBytes());
        header.putInt(36 + dataSize);
        header.put("WAVE".getBytes());

        // fmt chunk
        header.put("fmt ".getBytes());
        header.putInt(16); // fmt chunk size
        header.putShort((short) 1); // audio format (PCM)
        header.putShort((short) 1); // number of channels
        header.putInt(16000); // sample rate
        header.putInt(32000); // byte rate
        header.putShort((short) 2); // block align
        header.putShort((short) 16); // bits per sample

        // data chunk
        header.put("data".getBytes());
        header.putInt(dataSize);

        return header.array();
    }
}
